#include "hal_pwm.h"

extern void (*pwm_update_ck)(void);

void hal_pwm_init(struct hal_pwm_type *pwm)
{
	TIM_OCInitTypeDef TIM_OCInitStructure={0};
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure={0};
    NVIC_InitTypeDef        NVIC_InitStructure = {0};

    int hz = pwm->frq;

    switch((uint32_t)(pwm->tim))
    {
        case (uint32_t)(TIM1):
            RCC_APB2PeriphClockCmd( RCC_APB2Periph_TIM1, ENABLE );
            break;
        case (uint32_t)(TIM2):
            RCC_APB1PeriphClockCmd( RCC_APB1Periph_TIM2, ENABLE );
            break;
        case (uint32_t)(TIM3):
            RCC_APB1PeriphClockCmd( RCC_APB1Periph_TIM3, ENABLE );
            break;
        case (uint32_t)(TIM4):
            RCC_APB1PeriphClockCmd( RCC_APB1Periph_TIM4, ENABLE );
            break;
        case (uint32_t)(TIM5):
            RCC_APB1PeriphClockCmd( RCC_APB1Periph_TIM5, ENABLE );
            break;  
        default:
            break;                                      
    }
    pwm->pin->init(GPIO_Mode_AF_PP);    
	TIM_TimeBaseInitStructure.TIM_Period = SystemCoreClock / hz - 1;
	TIM_TimeBaseInitStructure.TIM_Prescaler = 0;
	TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
	TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_TimeBaseInit( pwm->tim, &TIM_TimeBaseInitStructure);

    if(pwm->callback)
    {
        pwm_update_ck = pwm->callback;
        TIM_ITConfig(pwm->tim, TIM_IT_Update, ENABLE);

        switch((uint32_t)pwm->tim)
        {
            case (uint32_t)TIM1:
                NVIC_InitStructure.NVIC_IRQChannel = TIM1_UP_IRQn;
                break;
            case (uint32_t)TIM2:
                NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
                break;
            case (uint32_t)TIM3:
                NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;
                break;
            case (uint32_t)TIM4:
                NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn;
                break;
            case (uint32_t)TIM5:
                NVIC_InitStructure.NVIC_IRQChannel = TIM5_IRQn;
                break;                                                             
        }
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
        NVIC_Init(&NVIC_InitStructure);
    }

    TIM_OCInitStructure.TIM_OCMode = HAL_DEFAULT_PWM_MODE;

	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
	TIM_OCInitStructure.TIM_Pulse = 0;
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
    switch(pwm->channel)
    {
        case (uint8_t)HAL_OC1:
            TIM_OC1Init( pwm->tim, &TIM_OCInitStructure );
            TIM_OC1PreloadConfig( pwm->tim, TIM_OCPreload_Disable );
            break;
        case (uint8_t)HAL_OC2:
            TIM_OC2Init( pwm->tim, &TIM_OCInitStructure );
            TIM_OC2PreloadConfig( pwm->tim, TIM_OCPreload_Disable );
            break;
        case (uint8_t)HAL_OC3:
            TIM_OC3Init( pwm->tim, &TIM_OCInitStructure );
            TIM_OC3PreloadConfig( pwm->tim, TIM_OCPreload_Disable );
            break;
        case (uint8_t)HAL_OC4:
            TIM_OC4Init( pwm->tim, &TIM_OCInitStructure );
            TIM_OC4PreloadConfig( pwm->tim, TIM_OCPreload_Disable );
            break;                            
    }

	TIM_CtrlPWMOutputs(pwm->tim, ENABLE );
	TIM_ARRPreloadConfig( pwm->tim, ENABLE );
	TIM_Cmd( pwm->tim, ENABLE );
}
void hal_pwm_start(struct hal_pwm_type *pwm)
{
    TIM_CtrlPWMOutputs(pwm->tim, ENABLE );
	TIM_Cmd( pwm->tim, ENABLE );    
}
void hal_pwm_pause(struct hal_pwm_type *pwm)
{
    TIM_CtrlPWMOutputs(pwm->tim, DISABLE );
	TIM_Cmd( pwm->tim, DISABLE );      
}
void hal_pwm_set_duty(struct hal_pwm_type *pwm,uint8_t duty)
{
    uint32_t t = SystemCoreClock / pwm->frq * duty / 100; 
    *((&(pwm->tim->CH1CVR)) + 2 * pwm->channel) = (uint16_t)t;
}